人员雇佣

Time Limit: 20 Sec Memory Limit: 259 MB

Description

作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司。这些经理相互之间合作有一个贡献指数,(我们用Ei,j表示i经理对j经理的了解程度),即当经理i和经理j同时被雇佣时,经理i会对经理j做出贡献,使得所赚得的利润增加Ei,j。当然,雇佣每一个经理都需要花费一定的金钱Ai,对于一些经理可能他做出的贡献不值得他的花费,那么作为一个聪明的人,小L当然不会雇佣他。 然而,那些没有被雇佣的人会被竞争对手所雇佣,这个时候那些人会对你雇佣的经理的工作造成影响,使得所赚得的利润减少Ei,j(注意:这里的Ei,j与上面的Ei,j 是同一个)。 作为一个效率优先的人,小L想雇佣一些人使得净利润最大。你可以帮助小L解决这个问题吗?

Input

第一行有一个整数N<=1000表示经理的个数 第二行有N个整数Ai表示雇佣每个经理需要花费的金钱 接下来的N行中一行包含N个数,表示Ei,j,即经理i对经理j的了解程度。(输入满足Ei,j=Ej,i)

Output

第一行包含一个整数,即所求出的最大值。

Sample Input

​   3
​   3 5 100
​   0 6 1
​   6 0 2
​   1 2 0

Sample Output

​   1

HINT

20%的数据中 N<=10
  50%的数据中 N<=100
  100%的数据中 N<=1000 , Ei,j<=maxlongint , Ai<=maxlongint

Main idea

给定若干关系,选择一个人需要固定的费用,对于i,j,选择了其中一个则损失E[i][j],两个都选了则获得2*E[i][j],问能获得的最大价值。

Solution

显然就是一个最小割的模型,我们直接套用论文里面的模型即可。

针对于这道题,我们对于代价建图,用Ans=总和-最小代价即可。

对于第i个点,如果选了,会损失a[i],连边**(S,i,a[i]):表示选了它之后的代价;如果不选,会损失ΣE[i][j],所以连边(i,T,ΣE[i][j])**,表示不选的损失。

然后对于一对点i,j,连边**(i,j,2*E[i][j])**,表示如果不选i,选了j的话,本来i中选j的利益得不到,又要损失j对i的影响为E[i][j],一共损失了2*E[i][j]。

然后求一下最小割即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include<bits/stdc++.h>
using namespace std;

typedef long long s64;
const int ONE=5000005;
const s64 INF=21474836400000;

int n,x;
s64 res;
int tou,wei,S,T;
int Dep[ONE],q[1000001],E[ONE];
int next[ONE],first[ONE],go[ONE],tot;
s64 w[ONE];
s64 Ans;

int get()
{
int res=1,Q=1;char c;
while( (c=getchar())<48 || c>57 )
if(c=='-')Q=-1;
res=c-48;
while( (c=getchar())>=48 && c<=57 )
res=res*10+c-48;
return res*Q;
}

int Add(int u,int v,s64 z)
{
next[++tot]=first[u]; first[u]=tot; go[tot]=v; w[tot]=z;
next[++tot]=first[v]; first[v]=tot; go[tot]=u; w[tot]=0;
}

int Bfs()
{
memset(Dep,0,sizeof(Dep));
tou=0; wei=1;
q[1]=S; Dep[S]=1;
for(int i=S;i<=T;i++) E[i]=first[i];
while(tou<wei)
{
int u=q[++tou];
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(Dep[v] || !w[e]) continue;
Dep[v]=Dep[u]+1;
q[++wei]=v;
}
}
return (Dep[T]>0);
}

s64 Dfs(int u,s64 Limit)
{
if(u==T || !Limit) return Limit;
s64 from=0,f;
for(int &e=E[u];e;e=next[e])
{
int v=go[e];
if(Dep[v]!=Dep[u]+1 || !w[e]) continue;
f=Dfs(v,min(Limit,w[e]));
w[e]-=f;
w[((e-1)^1)+1]+=f;
Limit-=f;
from+=f;
if(!Limit) break;
}
return from;
}

int main()
{
n=get();
S=0; T=n+1;
for(int i=1;i<=n;i++)
{
x=get();
Add(S,i,x);
}

for(int i=1;i<=n;i++)
{
res=0;
for(int j=1;j<=n;j++)
{
x=get();
res+=x; Ans+=x;
Add(i,j,2*x);
}
Add(i,T,res);
}

while(Bfs()) Ans-=Dfs(S,INF);

printf("%lld",Ans);

}